package cn.tedu.mall.seckill.timer;

import cn.tedu.mall.common.exception.CoolSharkServiceException;
import cn.tedu.mall.common.restful.ResponseCode;
import cn.tedu.mall.pojo.seckill.model.SeckillSku;
import cn.tedu.mall.pojo.seckill.model.SeckillSpu;
import cn.tedu.mall.seckill.mapper.SeckillSkuMapper;
import cn.tedu.mall.seckill.mapper.SeckillSpuMapper;
import cn.tedu.mall.seckill.utils.SeckillCacheUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.math.RandomUtils;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Slf4j
public class InitSeckillJob implements Job {
    //spu持久层
    @Autowired
    private SeckillSpuMapper seckillSpuMapper;
    //sku持久层
    @Autowired
    private SeckillSkuMapper seckillSkuMapper;
    //redis相关
    @Autowired
    private RedisTemplate redisTemplate;//将数据进行二进制格式保存，不能直接进行加减操作。随机码不需要。但是库存数需要
    @Autowired
    private StringRedisTemplate stringRedisTemplate;//以字符串形式保存，可以直接加减操作。用于保存库存数

    //实现预热工作,设计秒杀开始前五分钟进行缓存预热工作
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        //1.检查当前时间五分钟后，是否秒杀开始
        LocalDateTime time = LocalDateTime.now().plusMinutes(5);
        List<SeckillSpu> seckillSpus = seckillSpuMapper.selectSeckillSpusByTime(time);
        //seckillSpus如果为null，则秒杀活动未开始
        if(seckillSpus==null)
            throw new CoolSharkServiceException(ResponseCode.BAD_REQUEST,"秒杀活动未开始");
        //2.seckillSpus不为null，开始缓存预热
        for (SeckillSpu seckillSpu : seckillSpus) {
            //3.获取spuId，根据spuId获取sku列表
            Long spuId = seckillSpu.getSpuId();
            List<SeckillSku> seckillSkus = seckillSkuMapper.selectSkusBySpuId(spuId);
            //4.获取sku对应的库存数
            for (SeckillSku seckillSku : seckillSkus) {
                Long skuId = seckillSku.getSkuId();
                log.info("开始将{}号商品的库存数缓存到Redis中",skuId);
                //5.根据skuId获取到对应的key的名称
                String stockKey = SeckillCacheUtils.getStockKey(skuId);
                //6.检查redis中是否包含该key
                if(redisTemplate.hasKey(stockKey)){
                    log.info("{}号商品的库存数已经缓存进redis了",skuId);
                }else{
                    //7.如果key不存在，缓存进redis中
                    stringRedisTemplate.boundValueOps(stockKey).set(seckillSku.getSeckillStock()+"",
                            24*60*60 + RandomUtils.nextInt(100), TimeUnit.SECONDS);
                    log.info("{}号商品的库存数缓存进redis中",skuId);
                }
            }
            //8.生成随机码进行缓存
            //获取随机码的key
            String randCodeKey = SeckillCacheUtils.getRandCodeKey(spuId);
            //9.检查随机码是否存在
            if(redisTemplate.hasKey(randCodeKey)){
               int randCode = (int) redisTemplate.boundValueOps(randCodeKey).get();
               log.info("{}号商品的随机码已经存在，值是{}",spuId,randCode);
            }else{
                //10.生成随机码进行缓存
                int randCode = RandomUtils.nextInt(900000) + 100000;
                redisTemplate.boundValueOps(randCodeKey).set(randCode,
                        24*60*60 + RandomUtils.nextInt(100),TimeUnit.SECONDS);
                log.info("{}号商品的随机码进行缓存，值是{}",spuId,randCode);
            }
        }
    }
}
